/**
 * @Project: gateway
 * @Title: CertUtil.java
 * @Package com.hundsun.epay.eps.gateway.util
 * @Description: CertUtil.java
 * @author Administrator fansg@hundsun.com
 * @date 2014-4-2 下午02:59:08
 * @Copyright: 2014 www.hundsun.com All Rights Reserved.
 * @version V1.0.0.0 
 */
package com.hundsun.epay.pay.certkey;

import com.hundsun.epay.pay.CodeUtil;
import com.hundsun.epay.pay.EnumSignType;
import com.hundsun.epay.pay.PropertiesUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * @ClassName CertUtil
 * @Description CertUtil
 * @author Administrator fansg@hundsun.com
 * @date 2014-4-2
 */
@SuppressWarnings("JavaDoc")
public class CertUtil extends AbstractSignUtil {
	
	
	private static final Log log = LogFactory.getLog(CertUtil.class);

	public static String getStackTrace() {
		StringBuilder stackBuilder = new StringBuilder();

		StackTraceElement[] stack = new Throwable().getStackTrace();
		for (int index = 0; index < stack.length; index++) {
			StackTraceElement ste = stack[index];
			String stInfo = String.format("at %s.<%s>(%s:%d)", new Object[] {
					ste.getClassName(), ste.getMethodName(), ste.getFileName(),
					Integer.valueOf(ste.getLineNumber()) });

			stackBuilder.append(stInfo);
			stackBuilder.append("\r\n");
		}

		return stackBuilder.toString();
	}

	/**
	 * 读取证书KeyStore信息
	 * @Method: loadKeyStore 
	 * @Description: 读取证书KeyStore信息
	 * @param type "PKCS12"或"JKS"
	 * @param keystoreFile 证书文件绝对路径名称
	 * @param keystorePassword 证书密码
	 * @return KeyStore信息
	 * @throws Exception
	 */
	public static KeyStore loadKeyStore(String type, String keystoreFile, String keystorePassword) throws Exception {
		FileInputStream is = null;
		try {
			log.debug("私钥文件路径：" + keystoreFile + "\n私钥文件类型：" + type);
			File file = new File(keystoreFile);
			is = new FileInputStream(file);
			KeyStore keystore = KeyStore.getInstance(type);
			keystore.load(is, keystorePassword.toCharArray());
			return keystore;
		} catch (Exception e) {
			log.error("读取私钥文件出错！");
			e.printStackTrace();
			throw e;
		} finally {
			try {
				if (is != null)
					is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			is = null;
		}
	}
	
	/**
	 * 读取私钥证书文件
	 * @Method: readPrivateKey 
	 * @Description: 
	 * @param type 私钥文件证书类型
	 * @param keystoreFile 私钥文件路径
	 * @param keystorePassword 私钥文件密码
	 * @param keyAlias 私钥文件证书别名 alias
	 * @return
	 * @throws Exception
	 */
	public static PrivateKey readPrivateKey(String type, String keystoreFile, String keystorePassword, String keyAlias) throws Exception {
		KeyStore keystore = loadKeyStore(type, keystoreFile, keystorePassword);
        return (PrivateKey) keystore.getKey(keyAlias, keystorePassword.toCharArray());
	}
	
	/**
	 * 读取私钥证书文件
	 * @Method: readPrivateKeyFromX509 
	 * @Description: 
	 * @param type 私钥文件证书类型
	 * @param keystoreFile 私钥文件路径
	 * @param keystorePassword 私钥文件密码
	 * @return
	 * @throws Exception
	 */
	public static PrivateKey readPrivateKeyFromX509(String type, String keystoreFile, String keystorePassword) throws Exception {
		KeyStore keystore = loadKeyStore(type, keystoreFile, keystorePassword);
		PrivateKey priKey = null;

		try {
			@SuppressWarnings("rawtypes")
			Enumeration enumeration = keystore.aliases();
			String alias = null;
			for (int i = 0; enumeration.hasMoreElements(); i++) {
				alias = enumeration.nextElement().toString();
				Certificate[] certs = keystore.getCertificateChain(alias);
				if (certs != null) {
					log.debug("Certificate chain '" + alias + "':");
//					keystore.setKeyEntry(alias, priKey, keystorePassword.toCharArray(), certs);
					for (int c = 0; c < certs.length; c++) {
						if (certs[c] instanceof X509Certificate) {
							X509Certificate cert = (X509Certificate) certs[c];
							log.debug("=================================");
							log.debug("    Certificate[" + (c + 1) + "]:");
							log.debug("Subject DN: " + cert.getSubjectX500Principal());
							log.debug("Signature Algorithm: " + cert.getSigAlgName());
							log.debug("Valid from: " + cert.getNotBefore());
							log.debug("Valid until: " + cert.getNotAfter());
							log.debug("Issuer: " + cert.getIssuerDN());

							priKey = (PrivateKey) keystore.getKey(alias, keystorePassword.toCharArray());
							return priKey;
						}
					}
				}
				log.info("此文件中含有多个私钥证书！");
			}
			log.debug("alias-->" + alias);
			priKey = (PrivateKey) keystore.getKey(alias, keystorePassword.toCharArray());
//			log.debug(new String(priKey.getEncoded()));
		} catch (Exception e) {
			log.error("读取私钥证书文件出错，获取密钥失败！", e);
			e.printStackTrace();
			throw e;
		}
		return priKey;
	}
	
	/**
	 * 从公钥文件路径读取公钥
	 * @Method: readPublicKeyFromFileWithX509 
	 * @Description: 
	 * @param certFile
	 * @return PublicKey
	 * @throws Exception 
	 */
	public static PublicKey readPublicKeyFromFileWithX509(String certFile) throws Exception {
		PublicKey publicKey = null;
		InputStream is = null;
		try {
			is = new FileInputStream(certFile);

			CertificateFactory cf = CertificateFactory.getInstance(X509_CERT_NAME);
			Certificate cert = cf.generateCertificate(is);

			publicKey = cert.getPublicKey();

		} catch (Exception e) {
			throw new RuntimeException(e.getMessage(), e);
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
				is = null;
			}
		}

		return publicKey;
	}
	
	/**
	 * 读取公钥证书内容
	 * @param buffer 公钥证书字节流
	 * @param base64 (true：BASE64编码格式 false：DER编码二进制格式)
	 * @return
	 * @throws Exception
	 */
	public static PublicKey readPublicKeyFromX509(byte[] buffer, boolean base64)
			throws Exception {
		PublicKey localPublicKey = null;
		ByteArrayInputStream bais = null;
		try {
			if (base64) {
				bais = new ByteArrayInputStream(Base64.decodeBase64(buffer));
			} else {
				bais = new ByteArrayInputStream(buffer);
			}
			CertificateFactory factory = CertificateFactory.getInstance(X509_CERT_NAME);
			Certificate cert = factory.generateCertificate(bais);

			localPublicKey = cert.getPublicKey();
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("读取公钥证书内容失败", e);
		} finally {
			if (null != bais) {
				try {
					bais.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				bais = null;
			}
		}
		return localPublicKey;
	}
	
	/**
	 * 读取公钥证书内容
	 * @Method: readPublicKeyFromX509File 
	 * @Description: 
	 * @param certFile 公钥证书.cer文件（绝对路径）
	 * @return
	 * @throws Exception
	 */
	public static PublicKey readPublicKeyFromX509File(String certFile) throws Exception {
		log.debug("读取公钥文件证书：" + certFile);

		PublicKey localPublicKey = null;
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(certFile);
			CertificateFactory factory = CertificateFactory.getInstance(X509_CERT_NAME);
			Certificate cert = factory.generateCertificate(inputStream);

			localPublicKey = cert.getPublicKey();
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("读取公钥证书内容失败", e);
		} finally {
			if (null != inputStream) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				inputStream = null;
			}
		}
		return localPublicKey;
	}

	/**
	 * 读取DER编码二进制格式公钥证书
	 * @param certFile
	 * @return
	 * @throws Exception
	 */
	public static PublicKey readPublicKeyFromX509(String certFile) throws Exception {
		log.debug("读取公钥文件证书：" + certFile);
		PublicKey publicKey = null;
		try {
			publicKey = readPublicKeyFromX509(certFile, false);
		} catch (Exception e) {
			log.error("读取公钥文件失败", e);

			publicKey = readPublicKeyFromFileWithX509(certFile);
		}

		return publicKey;
	}
	
	/**
	 * 读取公钥证书内容
	 * @param certFile 公钥证书.cer文件（绝对路径）
	 * @param base64 (true：BASE64编码格式 false：DER编码二进制格式)
	 * @return 公钥证书
	 * @throws Exception
	 */
	public static PublicKey readPublicKeyFromX509(String certFile, boolean base64) throws Exception {
		File file = new File(certFile);
		if (!file.exists()) {
			throw new Exception(String.format("指定的公钥文件【%s】不存在", new Object[] { certFile }));
		}
		FileInputStream fis = null;
		FileReader fileReader = null;
		BufferedReader buffReader = null;
		try {
			byte[] buffer = null;

			if (base64) {
				fileReader = new FileReader(file);
				buffReader = new BufferedReader(fileReader);

				StringBuffer strBuff = new StringBuffer();
				List<String> lines = new ArrayList<String>();
				String curLine = null;

				while (null != (curLine = buffReader.readLine())) {
					lines.add(curLine);
				}
				/** 去掉首行信息"-----BEGIN CERTIFICATE-----" */
				/** 去掉尾行信息"-----END CERTIFICATE-----" */
				int lenSize = lines.size() - 1;
				for (int len = 1; len < lenSize; ++len) {
					strBuff.append(lines.get(len));
				}
				buffer = strBuff.toString().getBytes();
			} else {
				fis = new FileInputStream(file);
				int length = fis.available();
				buffer = new byte[length];
				int bytesRead = 0;
				while (bytesRead < length) {
					bytesRead += fis.read(buffer, bytesRead, length - bytesRead);
				}
			}

			return readPublicKeyFromX509(buffer, base64);
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception(String.format("读取证书文件【%s】失败", new Object[] { certFile }), e);
		} finally {
			if (null != buffReader) {
				try {
					buffReader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				buffReader = null;
			}
			if (null != fileReader) {
				try {
					fileReader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				fileReader = null;
			}
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				fis = null;
			}
		}
	}

	public static byte[] Int2ByteArray(int iSource) {
		byte[] bLocalArr = new byte[4];
		for (int i = 0; i < 4; i++) {
			bLocalArr[i] = (byte) (iSource >> 8 * i & 0xFF);
		}
		return bLocalArr;
	}

	public static int ByteArray2Int(byte[] bRefArr) {
		int iOutcome = 0;

		for (int i = 0; i < 4; i++) {
			byte bLoop = bRefArr[i];
			iOutcome += ((bLoop & 0xFF) << 8 * i);
		}

		return iOutcome;
	}
	
	/**
	 * 非对称密钥签名，生成BASE64编码后的签名串，支持MD5/RSA/DSA/SHA1WithRSA算法
	 * @Method: keyPairSign 
	 * @Description: 
	 * @param charset 字符编码，默认UTF-8
	 * @param content 待签名字符串
	 * @param priKey 签名私钥
	 * @param algorithms 签名算法
	 * @param code Base64编码方式
	 * @return
	 * @throws Exception
	 */
	public static String keyPairSign(String charset, String content, PrivateKey priKey, String algorithms, int code) throws Exception {
		if (null == charset || "".equals(charset)) {
			charset = DEFAULT_CHARSET;
		}
		try {
            Signature signature = Signature.getInstance(algorithms);
            signature.initSign(priKey);
            signature.update(content.getBytes(charset));
            
			switch (code) {
			case 0:
				return new String(Base64.encodeBase64(signature.sign(), false), charset);
			case 1:
				sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
				return encoder.encode(signature.sign());
			default:
			}
            return new String(Base64.encodeBase64(signature.sign(), false), charset);
        } catch(Exception e){
        	e.printStackTrace();
        	throw new Exception("签名出错!", e);
        }
	}
	
	/**
	 * 非对称密钥签名，生成BASE64编码后的签名串，支持MD5/RSA/DSA/SHA1WithRSA算法
	 * @param content 待签名字符串
	 * @param priKey 签名私钥
	 * @param algorithms 签名算法
	 * @return
	 */
	public static String keyPairSign(String content, PrivateKey priKey, String algorithms) throws Exception {
		return keyPairSign(DEFAULT_CHARSET, content, priKey, algorithms, 0);
//		try {
//            Signature signature = Signature.me(algorithms);
//            signature.initSign(priKey);
//            signature.update(content.getBytes(DEFAULT_CHARSET));
//            return new String(Base64.encodeBase64(signature.sign(), false), DEFAULT_CHARSET);
//        } catch(Exception e){
//        	e.printStackTrace();
//        	throw new Exception("签名出错!", e);
//        }
	}

	/**
	 * 非对称密钥签名，生成BASE64编码后的签名串，采用SHA1WithRSA算法
	 * @param content 待签名字符串
	 * @param priKey 签名私钥
	 * @return
	 */
	public static String keyPairSign(String content, PrivateKey priKey) throws Exception {
		return keyPairSign(content, priKey, SHA_RSA_SIGN_ALGORITHMS);
	}	
	/**
	 * 
	 * @Method: getSignMulRecordDeal 
	 * @Description:获得签文
	 * @param unSigncontent
	 * @param privateKey
	 * @return
	 */
	public static String getSignMulRecordDeal(String unSigncontent, PrivateKey privateKey) throws Exception{
		String sign="";
		if(unSigncontent.contains(CodeUtil.MULCONNECTOR)){			
			sign= keyPairSign(unSigncontent,privateKey);
		}else{
			Map<String,String> map=sortLinkedStringRemoveSign(unSigncontent);
			String s1=map.get("sortLinkedStr");			
			sign= keyPairSign(s1,privateKey);
		}
		return sign;
	}
	
	/**
	 * 
	 * @Method: keyPairSignMulRecordDeal 
	 * @Description:多笔与单笔加签处理
	 * @param unSigncontent
	 * @param privateKey
	 * @return
	 */
	public static String keyPairSignMulRecordDeal(String unSigncontent, PrivateKey privateKey) throws Exception{
		String returnStr="";
		if(unSigncontent.contains(CodeUtil.MULCONNECTOR)){

			
			String sign= keyPairSign(unSigncontent,privateKey);
			String signStr=CodeUtil.CONNECTOR+CodeUtil.SIGNTYPE+CodeUtil.ASSIGNMENT+EnumSignType.RSA.getCode()+CodeUtil.CONNECTOR+CodeUtil.SIGN+CodeUtil.ASSIGNMENT+sign;

			int index=unSigncontent.indexOf(CodeUtil.MULCONNECTOR);
			returnStr=unSigncontent.substring(0, index)+signStr+unSigncontent.substring(index);
		}else{
			Map<String,String> map=sortLinkedStringRemoveSign(unSigncontent);
			String s1=map.get("sortLinkedStr");
			
			String sign= keyPairSign(s1,privateKey);
			String signStr=CodeUtil.CONNECTOR+CodeUtil.SIGNTYPE+CodeUtil.ASSIGNMENT+EnumSignType.RSA.getCode()+CodeUtil.CONNECTOR+CodeUtil.SIGN+CodeUtil.ASSIGNMENT+sign;

			returnStr=s1+signStr;
		}
		return returnStr;
	}
	/**
	 * 非对称密钥签名，生成BASE64编码后的签名串，采用SHA1WithRSA算法
	 * @param unSigncontent 待签名字符串
	 * @return
	 */
	public static String keyPairSign4Merchant(String unSigncontent) throws Exception {
		PrivateKey privateKey=CertUtils.getPrivateKeyByPfx(PropertiesUtil.merchantPrivateKeyFile, PropertiesUtil.merchantPrivateKeyPassword);

        return keyPairSignMulRecordDeal(unSigncontent,privateKey);
	}	
	/**
	 * 非对称密钥签名，生成BASE64编码后的签名串，采用SHA1WithRSA算法
	 * @param privateKeyPath 私钥路径
	 * @param privatePwd	私钥密码
	 * @param unSigncontent 待签名字符串
	 * @return
	 */
	public static String keyPairSignWidthPriPwd4Merchant(String privateKeyPath,String privatePwd,String unSigncontent) throws Exception {
		PrivateKey privateKey=CertUtils.getPrivateKeyByPfx(privateKeyPath, privatePwd);
        return keyPairSignMulRecordDeal(unSigncontent,privateKey);
	}
	/**
	 * 
	 * @Method: getSign4Jschina 
	 * @Description:获得sign值
	 * @param unSigncontent
	 * @return
	 * @throws Exception
	 */
	public static String getSign4Jschina(String unSigncontent) throws Exception {
		PrivateKey privateKey=CertUtils.getPrivateKeyByPfx(PropertiesUtil.jschinaPrivateKeyFile, PropertiesUtil.jschinaPrivateKeyPassword);
        return getSignMulRecordDeal(unSigncontent,privateKey);
	}	
	/**
	 * 
	 * @Method: getSign4Merchant 
	 * @Description: 获得sign值
	 * @param unSigncontent
	 * @return
	 * @throws Exception
	 */
	public static String getSign4Merchant(String unSigncontent) throws Exception {
		PrivateKey privateKey=CertUtils.getPrivateKeyByPfx(PropertiesUtil.merchantPrivateKeyFile, PropertiesUtil.merchantPrivateKeyPassword);
        return getSignMulRecordDeal(unSigncontent,privateKey);
	}	
	/**
	 * 
	 * @Method: getSignWidthPriPwd4Merchant 
	 * @Description: 获得sign值
	 * @param privateKeyPath
	 * @param privatePwd
	 * @param unSigncontent
	 * @return
	 * @throws Exception
	 */
	
	public static String getSignWidthPriPwd4Merchant(String privateKeyPath,String privatePwd,String unSigncontent) throws Exception {
		PrivateKey privateKey=CertUtils.getPrivateKeyByPfx(privateKeyPath, privatePwd);
		String sign=getSignMulRecordDeal(unSigncontent,privateKey);
		return sign;
	}
	
	/**
	 * 非对称密钥签名，生成BASE64编码后的签名串，采用SHA1WithRSA算法
	 * @param unSigncontent 待签名字符串
	 * @return
	 */
	public static String keyPairSign4Jschina(String unSigncontent) throws Exception {
		PrivateKey privateKey=CertUtils.getPrivateKeyByPfx(PropertiesUtil.jschinaPrivateKeyFile, PropertiesUtil.jschinaPrivateKeyPassword);
        return keyPairSignMulRecordDeal(unSigncontent,privateKey);
	}	
	
	public static boolean verifyPrivateKeyPassword(String privateKeyPath,String privatePwd) throws Exception {
		boolean isSuccess=false;
		
		PrivateKey privateKey=CertUtils.getPrivateKeyByPfx(privateKeyPath, privatePwd);
		if(privateKey!=null)
			isSuccess=true;
		
		return isSuccess;
	}
	/**
	 * 验证非对称密钥签名
	 * @Method: verifyKeyPairSign 
	 * @Description: 
	 * @param charset 字符编码，默认UTF-8
	 * @param unsignedContent 原字符串（未签名）
	 * @param signedContent 签名后字符串
	 * @param pubKey 公钥
	 * @param algorithms 算法
	 * @param code Base64编码方式
	 * @return
	 * @throws Exception
	 */
	public static boolean verifyKeyPairSign(String charset, String unsignedContent, String signedContent, PublicKey pubKey, String algorithms, int code) throws Exception {
		boolean result = false;
		if (null == charset || "".equals(charset)) {
			charset = DEFAULT_CHARSET;
		}
		try {
			Signature signature = Signature.getInstance(algorithms);
			signature.initVerify(pubKey);
			signature.update(unsignedContent.getBytes(charset));
            
			switch (code) {
			case 0:
				log.debug("【Base64后的签名串：】" + new String(Base64.decodeBase64(signedContent), charset));
				result = signature.verify(Base64.decodeBase64(signedContent));
				break;
			case 1:
				sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
				log.debug("【Base64后的签名串：】" + new String(decoder.decodeBuffer(signedContent), charset));
				result = signature.verify(decoder.decodeBuffer(signedContent));
				break;
			default:
			}
        } catch(Exception e){
        	e.printStackTrace();
        	throw new Exception("签名出错!", e);
        }
        return result;
	}
	
	/**
	 * 验证签名合法性
	 * @Method: verifyKeyPairSign 
	 * @Description: 
	 * @param unsignedContent
	 * @param signedContent
	 * @param pubKey
	 * @return
	 * @throws Exception
	 */
	public static boolean verifyKeyPairSign(String unsignedContent, String signedContent, PublicKey pubKey) throws Exception {
		return verifyKeyPairSign(null, unsignedContent, signedContent, pubKey, SHA_RSA_SIGN_ALGORITHMS, 0);
	}
	
	/**
	 * 
	 * @Method: verifyKeyPairSign 
	 * @Description: 商户验签公共方法
	 * @param unsignedContent
	 * @param signedContent
	 * @return
	 * @throws Exception
	 */
	public static boolean verifyKeyPairSign4Merchant(String unsignedContent, String signedContent) throws Exception {
		PublicKey pubKey =CertUtils.getPublicKeyByCer4Merchant(PropertiesUtil.jschinaPublicKeyFile);
		return verifyKeyPairSign(unsignedContent, signedContent, pubKey);
	}
	
	public static boolean validateSignedContent(String signedContent) throws Exception{
		Boolean isValid=false;
		String exceptionMsg="";
		try{
		
			if(signedContent.contains(CodeUtil.SIGN+CodeUtil.ASSIGNMENT)&&signedContent.contains(CodeUtil.SIGNTYPE+CodeUtil.ASSIGNMENT)){
				int signTypeIndex=signedContent.indexOf(CodeUtil.SIGNTYPE+CodeUtil.ASSIGNMENT);
				
				String signType=signedContent.substring(signTypeIndex);
				if(!signType.contains(EnumSignType.RSA.getCode())){
					exceptionMsg="签文中signType目前仅支持RSA";
					throw new Exception("签文中signType目前仅支持RSA");
				}
				
				isValid=true;
			}else{
				exceptionMsg="签文中未包含sign或signType";
				throw new Exception("签文中未包含sign或signType");
			}
		}catch(Exception e){
			if("".equals(exceptionMsg))
				exceptionMsg="签文错误";
			throw new Exception(exceptionMsg);
		}
		return isValid;
	}
	/**
	 * 
	 * @Method: verifyKeyPairSign 
	 * @Description: 商户验签
	 * @param signedContent
	 * @return
	 * @throws Exception
	 */					  		
	public static boolean verifyKeyPairSign4Merchant(String signedContent) throws Exception {
		boolean flag;
//		log.debug("【待验签字符串：】"+signedContent);
		validateSignedContent(signedContent);
		
		
		if(signedContent.contains(CodeUtil.MULCONNECTOR)){
			int begin_index=signedContent.indexOf(CodeUtil.CONNECTOR+CodeUtil.SIGNTYPE+CodeUtil.ASSIGNMENT);
			int end_index=signedContent.indexOf(CodeUtil.MULCONNECTOR);
			String s1=signedContent.substring(0,begin_index)+signedContent.substring(end_index);
				
			String signstr=CodeUtil.CONNECTOR+CodeUtil.SIGN+CodeUtil.ASSIGNMENT;
			int sign_index=signedContent.indexOf(signstr);
			String s2=signedContent.substring(sign_index+signstr.length(),end_index);
			flag=verifyKeyPairSign4Merchant(s1,s2);
		}else{		
			Map<String,String> map=sortLinkedStringRemoveSign(signedContent);
			String s1=map.get("sortLinkedStr");
//			log.debug("【排序并去掉sign部分，字符串：】"+s1);
			String s2=map.get(CodeUtil.SIGN);
			flag=verifyKeyPairSign4Merchant(s1,s2);
		}
		return flag;
	}
	/**
	 * 验证签名合法性（提供支付平台调用）
	 * @Method: verifyKeyPairSign 
	 * @Description: 
	 * @param unsignedContent
	 * @param signedContent
	 * @param merchantPublicKeyFilePath
	 * @return
	 * @throws Exception
	 */
	public static boolean verifyKeyPairSign4Jschina(String unsignedContent, String signedContent,String merchantPublicKeyFilePath) throws Exception {
		PublicKey pubKey =CertUtils.getPublicKeyByCer4Jschina(merchantPublicKeyFilePath);
		return verifyKeyPairSign(unsignedContent, signedContent, pubKey);
	}
	/**
	 *  验证签名合法性（提供支付平台调用）
	 * @Method: verifyKeyPairSign 
	 * @Description: 验证签名合法性
	 * @param signedContent 签名字符串
	 * @param merchantPublicKeyFilePath 商户公钥文件路径
	 * @return
	 * @throws Exception
	 */
	public static boolean verifyKeyPairSign4Jschina(String signedContent,String merchantPublicKeyFilePath) throws Exception {
		validateSignedContent(signedContent);
		log.debug("【待验签字符串：】"+signedContent);
		Map<String,String> map=sortLinkedStringRemoveSign(signedContent);
		String s1=map.get("sortLinkedStr");
		log.debug("【排序并去掉sign部分，字符串：】"+s1);
		String s2=map.get(CodeUtil.SIGN);
        return verifyKeyPairSign4Jschina(s1,s2,merchantPublicKeyFilePath);
	}
	/**
	 * 
	 * @Method: sortLinkedString 
	 * @Description: 参数重新排序、并去掉signType和md5Sign 字段
	 * @param linkedString: 举例：a=a1&b=b1&signType=MD5&md5Sign=
	 * @return
	 * @throws Exception
	 */
	public static Map<String,String> sortLinkedStringRemoveSign(String linkedString)throws Exception{
		Map<String,String> resultMap= new HashMap<String,String>();
		
		String result="";
		String[] arrayParam=linkedString.split(CodeUtil.CONNECTOR);
		Map<String, String> map=new HashMap<String, String>();
		//获取所有键值对
		for(int i=0;i<arrayParam.length;i++){
			String param=arrayParam[i];
			if("".equals(param)){
				continue;
			}
			//获取第一个'='的位置
			int index=param.indexOf(CodeUtil.ASSIGNMENT, 0);
			String key="";
			String value="";
			if(index==-1){
				key=param.substring(0);
			}else{
				key=param.substring(0,index);
				value=param.substring(index+1);
			}
			if(CodeUtil.SIGN.equals(key)){
				resultMap.put(CodeUtil.SIGN, value);
			}
			//并去掉signType和md5Sign 字段
			if(!CodeUtil.SIGNTYPE.equals(key)&&!CodeUtil.SIGN.equals(key))
				map.put(key, value);
		}
		//按照键来进行排序
		String[] args=new String[map.size()];
		Set<String> keys=map.keySet();
		Iterator<String> iterator=keys.iterator();
		int i=0;
		while(iterator.hasNext()){
			args[i]=iterator.next();
			i++;
		}
		Arrays.sort(args);
		//重组url
		for(int j=0;j<args.length;j++){
			String key=args[j];
			String value=map.get(key);
			result+=CodeUtil.CONNECTOR+key+CodeUtil.ASSIGNMENT+value;
		}
		if(result.length()>0){
			result=result.substring(1);
		}
		resultMap.put("sortLinkedStr", result);
		return resultMap;
	}
	

}
